/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package uk.ac.susx.inf.ianw.shareManagement.services.impl;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.util.Calendar;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import uk.ac.susx.inf.ianw.shareManagement.CustomerIdentifier;
import uk.ac.susx.inf.ianw.shareManagement.PurchaseRequest;
import uk.ac.susx.inf.ianw.shareManagement.PurchaseResult;
import uk.ac.susx.inf.ianw.shareManagement.ShareBroker;
import uk.ac.susx.inf.ianw.shareManagement.constants.ShareManagementConstants;
import uk.ac.susx.inf.ianw.shareManagement.dto.PortfolioDetail;
import uk.ac.susx.inf.ianw.shareManagement.entities.ShareTransaction;
import uk.ac.susx.inf.ianw.shareManagement.locator.RMILocator;

@Stateless(name = "shareBrokerService")
public class ShareBrokerService {

    @EJB
    private ShareTransactionService shareTransactionService;

    public Double getPrice(String company) throws Exception {
        return RMILocator.getInstance().getShareBroker().getPrice(company);
    }

    public PortfolioDetail getPortfolioDetail(String company) throws Exception {
        PortfolioDetail detail = new PortfolioDetail();
        detail.setCompany(company);
        Double price = getPrice(company);
        Integer amount = shareTransactionService.getShareCount(company);
        detail.setPrice(price);
        detail.setAmount(amount);
        detail.setTotalValue(price * amount);
        return detail;
    }

    public void makePurchaseRequest(ShareTransaction transaction) throws Exception {
        //GET THE REMOTE OBJECT
        Registry registry = LocateRegistry.getRegistry(ShareManagementConstants.RMI_PORT);
        ShareBroker shareBroker = (ShareBroker) registry.lookup(ShareBroker.SHAREBROKER);

        //LOAD THE KEYSTORE
        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(getClass().getClassLoader().getResourceAsStream("keyStore/dsa_stock.keystore"),
                ShareManagementConstants.PASSWORD);

        //GET CUSTOMER IDENTIFIER
        CustomerIdentifier customerId = shareBroker.register(getCertificate(keyStore, ShareManagementConstants.ALIAS), "developer");

        //INIT A PURCHASE REQUEST
        PurchaseRequest request = new PurchaseRequest(customerId.getId(),
                System.currentTimeMillis(), transaction.getCompany(), transaction.getAmount());
        request.setSignature(null);

        //SIGN THE REQUEST
        PrivateKey privateKey = getPrivateKey(keyStore, ShareManagementConstants.ALIAS, ShareManagementConstants.PASSWORD);
        Signature signature = Signature.getInstance("SHA1withDSA", "SUN");
        signature.initSign(privateKey);
        byte[] requestBytes = getBytesFromObject(request);
        signature.update(requestBytes);
        request.setSignature(signature.sign());

        //MAKE THE REQUEST AND GET RESULT
        PurchaseResult result = shareBroker.buyShares(request);
        //VALIDATE RESULT
        PublicKey publicKey = customerId.getDealerCertificate().getPublicKey();
        Signature validateSignature = Signature.getInstance("SHA1withDSA", "SUN");
        validateSignature.initVerify(publicKey);
        byte[] currentSignature = result.getSignature();
        result.setSignature(null);
        validateSignature.update(getBytesFromObject(result));
        Boolean validateResult = validateSignature.verify(currentSignature);
        result.setSignature(currentSignature);
        if(validateResult == true){
            transaction.setPrice(result.getPrice());
            transaction.setPurchaseDate(Calendar.getInstance().getTime());
            shareTransactionService.create(transaction);
        }
    }

    /**
     * Get certificate from key store
     * @param keyStore
     * @param alias
     * @return
     * @throws KeyStoreException
     */
    private static Certificate getCertificate(KeyStore keyStore, String alias) throws KeyStoreException {
        return keyStore.getCertificate(alias);
    }

    /**
     * Write object to byte array
     * @param o
     * @return
     * @throws IOException
     */
    private static byte[] getBytesFromObject(Object o) throws IOException {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(o);
        return baos.toByteArray();
    }

    /**
     * Get private key from the keystore by alias
     * @param keyStore
     * @param alias
     * @param password
     * @return
     * @throws UnrecoverableKeyException
     * @throws KeyStoreException
     * @throws NoSuchAlgorithmException
     */
    private static PrivateKey getPrivateKey(KeyStore keyStore, String alias,
            char[] password) throws UnrecoverableKeyException,
            KeyStoreException, NoSuchAlgorithmException {
        return (PrivateKey) keyStore.getKey(alias, password);
    }
}
